summaryrefslogtreecommitdiffstats
path: root/prog/6/daemon.c
blob: 849ebb3c2fa274a87c94c2b8b4ee0b2fcad98178 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <poll.h>
#include <arpa/nameser.h>
#include <sys/uio.h>
#include <netdb.h>
#include <sys/types.h>
#include <resolv.h>
#include <errno.h>
#define DEBUG 1
int handle (unsigned char * packet, int bytes) {
	HEADER * header = (HEADER *) packet;
	ns_msg handle;
	if (ns_initparse(packet, bytes, &handle) == -1)
		return -1;
	if (header->qr) // response
		return -1;
	header->qr = 1;
	header->tc = 0;
	header->aa = 0;
	header->ra = 0;
	if (header->opcode) {
		header->rcode = NOTIMP;
		return bytes;
	}
	if (header->qdcount != 1) {
		header->rcode = FORMERR;
		return bytes;
	}
	ns_rr rr;
	if (ns_parserr(handle, ms_s_qd, 0, &rr) == -1) {
		header->rcode = FORMERR;
		return bytes;
	}
	
}
int main (int argc, char ** argv) {
	if (argc != 3) {
		fprintf(stderr, "%s port config\n"
	"	port:	53 (UDP listening port) (configurable to allow many daemons)\n"
	"	config:	file name of the configuration file (use 6c to check syntax)\n"
	"creates PTR and AAAA records with on-the-fly method (RFC 8501, section 2.5)\n"
	"an example of records created for IPv6 2001:db8:1\n"
	"	1.0.[...].0.8.B.D.0.1.0.0.2.IP6.ARPA. 127800 IN PTR	1.0.[...].0.8.B.D.0.1.0.0.2.IP6.ARPA.\n"
	"	1.0.[...].0.8.B.D.0.1.0.0.2.IP6.ARPA. 127800 IN AAAA	2001:db8::1\n"
	"more information:\n"
	"	- SOA serial will be the number of days since 2023-08-06\n"
	"	- refresh, retry and expire in SOA will have values conforming to standard, but\n"
	"	  they are irrelevant, as potential 6d slaves are not real DNS slaves\n"
	"	- negative cache TTL is 1337, this is irrelevant, as nxdomains aren't expected\n"
	"	- to exit after reading and printing out the configuration, run %s dry <config>\n"
		, argv[0]);
		return 1;
	}
	int sock = socket(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
	if (sock == -1) {
		perror("socket(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0)");
		return 2;
	}
	struct sockaddr_in6 listen = {
		.sin6_family = AF_INET6,
		.sin6_port = htons(53),
		.sin6_addr = IN6ADDR_ANY_INIT
	};
	if (bind(sock, (struct sockaddr *) &listen, sizeof listen) == -1) {
		perror("bind(sock, &listen, sizeof listen)");
		return 3;
	}
	struct pollfd pfd = {
		.fd = sock,
		.events = POLLIN
	};
	while (poll(&pfd, 1, -1) != -1) {
		if (pfd.revents & POLLERR) {
			fprintf(stderr, "POLLERR\n");
			return 5;
		}
		if (pfd.revents & POLLHUP) {
			fprintf(stderr, "POLLHUP\n");
			return 6;
		}
		if (pfd.revents & POLLNVAL) {
			fprintf(stderr, "POLLNVAL\n");
			return 7;
		}
		struct sockaddr_in6 sender;
		unsigned char packet[512];
		struct iovec parts[] = {
			{
				.iov_base = packet,
				.iov_len = sizeof packet
			}
		};
		struct msghdr msg = {
			.msg_name = &sender,
			.msg_namelen = sizeof sender,
			.msg_iov = parts,
			.msg_iovlen = sizeof parts/sizeof parts[0]
		};
		int bytes = recvmsg(sock, &msg, MSG_DONTWAIT | MSG_TRUNC);
		if (bytes == -1) {
			perror("recvmsg");
			return 8;
		}
		int len = handle(packet, bytes);
		if (len >= 0) {
			if (sendto(sock, packet, len, MSG_DONTWAIT | MSG_NOSIGNAL, (struct sockaddr *) &sender, sizeof sender) == -1 && errno != EACCES) {
				perror("sendto");
				return 9;
			}
		}
	}
	perror("poll");
	return 4; // there really is no successful exit code, this program should run indefinitely
}